use crate::ast::*;
use crate::error::{CompilerError, Result};
use inkwell::types::BasicTypeEnum;
use inkwell::values::{BasicMetadataValueEnum, BasicValueEnum};
use inkwell::AddressSpace;
use crate::llvm_backend::memory::PointerOrigin;
use crate::llvm_backend::LLVMBackend;

impl<'ctx> LLVMBackend<'ctx> {

    /// Generate function call
    pub(in crate::llvm_backend) fn generate_call_expression(
        &mut self,
        call: &CallExpr,
    ) -> Result<BasicValueEnum<'ctx>> {
        // Check if this is a Path expression (e.g., Result::Ok(42))
        if let Expression::Path(path_expr) = &*call.callee {
            if path_expr.segments.len() == 2 {
                let type_name = &path_expr.segments[0];
                let variant_name = &path_expr.segments[1];

                // Handle Result::Ok() and Result::Err() constructors
                if type_name == "Result" {
                    if variant_name == "Ok" || variant_name == "Err" {
                        return self.generate_result_constructor(variant_name, &call.arguments);
                    }
                }

                // Handle Option::Some() and Option::None constructors
                if type_name == "Option" {
                    if variant_name == "Some" || variant_name == "None" {
                        return self.generate_option_constructor(variant_name, &call.arguments);
                    }
                }

                // Handle enum variant constructors
                if self.enum_declarations.contains_key(type_name) {
                    // This is an enum variant constructor!
                    return self.generate_enum_variant_constructor(
                        type_name,
                        variant_name,
                        &call.arguments,
                    );
                }
            }
        }

        // Check if this is a function literal/pointer being called
        if let Expression::FunctionLiteral(func_lit) = &*call.callee {
            // Generate the function pointer value
            let func_ptr = self.generate_expression(&call.callee)?;
            // Call through the function pointer
            let func_type = if let Some(Type::Function(ft)) = &func_lit.function_type {
                Some(ft)
            } else {
                None
            };
            return self.generate_function_pointer_call(
                func_ptr,
                &call.arguments,
                func_type,
                call.location,
            );
        }

        // Check if this is a variable that holds a function pointer
        if let Expression::Variable(var_name) = &*call.callee {
            // Check if this variable has a function type
            let func_type_opt = self.variable_type_map.get(var_name).cloned();
            if let Some(Type::Function(func_type)) = func_type_opt {
                // This is a function pointer stored in a variable
                let func_ptr = self.generate_expression(&call.callee)?;
                return self.generate_function_pointer_call(
                    func_ptr,
                    &call.arguments,
                    Some(&func_type),
                    call.location,
                );
            }
        }

        let callee_name = match &*call.callee {
            Expression::Variable(name) => name,
            Expression::FieldAccess(field_access) => {
                // Check if this is an enum variant constructor (e.g., Result::Ok(42))
                if let Expression::Variable(enum_name) = &*field_access.object {
                    if self.enum_declarations.contains_key(enum_name) {
                        // This is an enum variant constructor!
                        return self.generate_enum_variant_constructor(
                            enum_name,
                            &field_access.field,
                            &call.arguments,
                        );
                    }
                }

                // Handle method calls like point.distance()
                return self.generate_method_call_expression(&MethodCallExpr {
                    object: field_access.object.clone(),
                    method: field_access.field.clone(),
                    type_args: call.type_args.clone(),
                    arguments: call.arguments.clone(),
                    location: call.location,
                });
            }
            Expression::MethodCall(method_call) => {
                // Handle static method calls like Person::new()
                // Create a new method call with the same arguments
                return self.generate_method_call_expression(&MethodCallExpr {
                    object: method_call.object.clone(),
                    method: method_call.method.clone(),
                    type_args: call.type_args.clone(),
                    arguments: call.arguments.clone(),
                    location: call.location,
                });
            }
            _ => {
                return Err(CompilerError::internal(&format!(
                    "Invalid function call: {:?}",
                    call.callee
                )));
            }
        };

        // 处理带前缀的函数调用 (如 io.println, aio.printf)
        let actual_function_name = if callee_name.contains('.') {
            // 提取点号后的实际函数名
            callee_name.split('.').last().unwrap_or(callee_name)
        } else {
            callee_name
        };

        // 特殊处理 println 和 print 函数
        if actual_function_name == "println" || actual_function_name == "print" {
            return self.generate_print_call(actual_function_name, &call.arguments);
        }

        // 特殊处理 assert 函数
        if actual_function_name == "assert" {
            return self.generate_assert_call(&call.arguments);
        }

        if actual_function_name == "assert_eq" {
            return self.generate_assert_comparison_call(
                &call.arguments,
                call.location,
                BinaryOp::Equal,
            );
        }

        if actual_function_name == "assert_ne" {
            return self.generate_assert_comparison_call(
                &call.arguments,
                call.location,
                BinaryOp::NotEqual,
            );
        }

        if actual_function_name == "assert_true" {
            return self.generate_assert_bool_call(&call.arguments, call.location, true);
        }

        if actual_function_name == "assert_false" {
            return self.generate_assert_bool_call(&call.arguments, call.location, false);
        }

        if actual_function_name == "assert_panics" {
            return self.generate_assert_panics_entry(&call.arguments, call.location);
        }

        // 特殊处理 free 函数 - 内存安全检查和复合类型递归释放
        if actual_function_name == "free" {
            if call.arguments.len() != 1 {
                return Err(CompilerError::internal(
                    "free() requires exactly 1 argument",
                ));
            }

            // Check if trying to free a stack pointer
            if let Expression::Variable(var_name) = &call.arguments[0] {
                if let Some(origin) = self.pointer_origin_map.get(var_name) {
                    if *origin == PointerOrigin::Stack {
                        return Err(CompilerError::semantic(
                            call.location.line,
                            call.location.column,
                            &format!(
                                "Cannot free stack pointer '{}'. \
                                Only heap-allocated pointers (from &Type{{}} syntax) can be freed. \
                                Stack pointers (from &variable syntax) are automatically managed.",
                                var_name
                            ),
                        ));
                    }
                }

                // Check if this is a pointer to a composite type that needs deep free
                if let Some(var_type) = self.variable_type_map.get(var_name).cloned() {
                    if let Type::Reference(ref_type) = var_type {
                        // If it's a pointer to a slice, need to free the internal array first
                        if let Type::Vec(_vector_type) = *ref_type.referenced_type {
                            return self.generate_deep_free_slice(var_name);
                        }
                        // String is currently i8* pointing to global constants, no deep free needed
                        // In the future, if we have heap-allocated strings, add handling here
                    }
                }
            }
            // If origin is Heap or Unknown, allow free() to proceed with regular free
        }

        let resolved_target_name = call.resolved.as_ref().map(|r| r.mangled_name.clone());

        // 首先尝试使用分派后的函数名
        let function = if let Some(target_name) = resolved_target_name {
            if let Some(func) = self.function_map.get(&target_name) {
                *func
            } else {
                return Err(CompilerError::internal(&format!(
                    "Undefined function: {}",
                    callee_name
                )));
            }
        } else if let Some(func) = self.function_map.get(callee_name) {
            *func
        } else if let Some(func) = self.function_map.get(actual_function_name) {
            *func
        } else {
            return Err(CompilerError::internal(&format!(
                "Undefined function: {}",
                callee_name
            )));
        };

        // Generate arguments
        let resolved_signature = call.resolved.as_ref().map(|resolved| &resolved.signature);
        let args: Vec<BasicMetadataValueEnum> = call
            .arguments
            .iter()
            .enumerate()
            .map(|(index, arg)| {
                // Check if this is a reference variable being passed to a function
                if let Expression::Variable(var_name) = arg {
                    if let Some(var_value) = self.variable_map.get(var_name) {
                        if let Some(var_type) = self.variable_type_map.get(var_name) {
                            if let Type::Reference(_) = var_type {
                                // For reference types, we need to pass the address that the reference points to
                                // This is similar to how method calls handle reference parameters
                                if var_value.is_pointer_value() {
                                    let ref_ptr = var_value.into_pointer_value();
                                    let ptr_type =
                                        self.context.i8_type().ptr_type(AddressSpace::default());
                                    let target_ptr = self.builder.build_load(
                                        ptr_type,
                                        ref_ptr,
                                        &format!("{}_target", var_name),
                                    )?;

                                    if let BasicValueEnum::PointerValue(actual_ptr) = target_ptr {
                                        return Ok(actual_ptr.into());
                                    } else {
                                        return Err(CompilerError::internal(
                                            "Reference should point to a valid address",
                                        ));
                                    }
                                }
                            }
                        }
                    }
                }

                // Default behavior: generate expression normally
                let mut value = self.generate_expression(arg)?;

                // Try to coerce argument to expected parameter type.
                // Prefer the resolved overload signature when available,
                // otherwise fall back to the recorded FunctionDecl (for
                // non-overloaded functions like print_sound).
                let mut target_param_type: Option<Type> = None;
                if let Some(signature) = resolved_signature {
                    if let Some(t) = signature.parameter_types.get(index) {
                        target_param_type = Some(t.clone());
                    }
                } else if let Expression::Variable(func_name) = &*call.callee {
                    if let Some(func_decl) = self.function_decls.get(func_name) {
                        if let Some(param_decl) = func_decl.parameters.get(index) {
                            target_param_type = Some(param_decl.param_type.clone());
                        }
                    }
                }

                if let Some(target_type) = target_param_type {
                    let inferred_type = self.infer_expression_type(arg);
                    value =
                        self.coerce_value_to_type(value, inferred_type.as_ref(), &target_type)?;
                }

                // 特殊处理free函数：将任何指针转换为i8*
                if actual_function_name == "free" {
                    if let BasicValueEnum::PointerValue(ptr_val) = value {
                        let i8_ptr_type = self.context.i8_type().ptr_type(AddressSpace::default());
                        value = self
                            .builder
                            .build_bitcast(ptr_val, i8_ptr_type, "free_ptr_cast")?
                            .into();
                    }
                }

                Ok(value.into())
            })
            .collect::<Result<Vec<_>>>()?;

        // Build call
        let call_result = self.builder.build_call(function, &args, "call");

        // Handle return value
        if function.get_type().get_return_type().is_none() {
            Ok(self.context.i32_type().const_int(0, false).into())
        } else {
            let result = call_result?.try_as_basic_value().left().unwrap();
            Ok(result)
        }
    }


    /// Generate Result constructor (Result::Ok(value) or Result::Err(error))
    fn generate_result_constructor(
        &mut self,
        variant_name: &str,
        arguments: &[Expression],
    ) -> Result<BasicValueEnum<'ctx>> {
        if arguments.len() != 1 {
            return Err(CompilerError::internal(&format!(
                "Result::{}() expects exactly 1 argument, got {}",
                variant_name,
                arguments.len()
            )));
        }

        // Generate the argument value
        let arg_value = self.generate_expression(&arguments[0])?;

        // Get the argument's NRC type from the expression to determine Result type parameters
        // Try to infer from expression, but if that fails, infer from the generated value
        let arg_nrc_type = self
            .infer_expression_type(&arguments[0])
            .or_else(|| {
                // Fallback: try to infer from the generated LLVM value
                match arg_value {
                    BasicValueEnum::IntValue(_) => {
                        Some(Type::Basic(crate::ast::types::BasicType::Int))
                    }
                    BasicValueEnum::FloatValue(fv) => {
                        if fv.get_type() == self.context.f32_type() {
                            Some(Type::Basic(crate::ast::types::BasicType::Float32))
                        } else {
                            Some(Type::Basic(crate::ast::types::BasicType::Float64))
                        }
                    }
                    BasicValueEnum::PointerValue(_) => {
                        Some(Type::Basic(crate::ast::types::BasicType::String))
                    }
                    _ => None,
                }
            })
            .ok_or_else(|| {
                CompilerError::internal("Cannot infer argument type for Result constructor")
            })?;

        // Get the argument's LLVM type
        let arg_llvm_type = self.nrc_type_to_llvm_type(&Some(arg_nrc_type.clone()))?;

        // For now, we'll create a simplified Result type
        // tag = 0 for Ok, tag = 1 for Err
        let tag_value = if variant_name == "Ok" {
            self.context.i32_type().const_int(0, false)
        } else {
            self.context.i32_type().const_int(1, false)
        };

        // Calculate the size needed for the data field
        let data_size = self.get_llvm_type_size(arg_llvm_type);

        // For now, we'll use a simplified approach
        // TODO: Get full Result type from context to handle both Ok and Err types properly
        // We need to know both types to create the correct Result type, but for now we'll use the argument type
        let data_type = self.context.i8_type().array_type(data_size.max(1) as u32);
        let result_struct_type = self.context.struct_type(
            &[
                self.context.i32_type().into(), // tag
                data_type.into(),               // data
            ],
            false,
        );

        // Allocate space for the Result value
        let result_alloca = self
            .builder
            .build_alloca(result_struct_type, "result_temp")?;

        // Set the tag field (index 0)
        let tag_ptr = unsafe {
            self.builder.build_gep(
                result_struct_type,
                result_alloca,
                &[
                    self.context.i32_type().const_zero(),
                    self.context.i32_type().const_zero(),
                ],
                "tag_ptr",
            )?
        };
        self.builder.build_store(tag_ptr, tag_value)?;

        // Set the data field (index 1)
        let data_ptr = unsafe {
            self.builder.build_gep(
                result_struct_type,
                result_alloca,
                &[
                    self.context.i32_type().const_zero(),
                    self.context.i32_type().const_int(1, false),
                ],
                "data_ptr",
            )?
        };

        // Convert the argument value to bytes and store in data field
        // We'll use memcpy or bitcast to store the value
        let data_i8_ptr = self.builder.build_pointer_cast(
            data_ptr,
            self.context.i8_type().ptr_type(AddressSpace::default()),
            "data_i8_ptr",
        )?;

        // Store the argument value by bitcasting and copying
        // Create a temporary alloca with the correct type
        let arg_value_ptr = match arg_llvm_type {
            BasicTypeEnum::IntType(it) => self.builder.build_alloca(it, "arg_temp")?,
            BasicTypeEnum::FloatType(ft) => self.builder.build_alloca(ft, "arg_temp")?,
            BasicTypeEnum::PointerType(pt) => self.builder.build_alloca(pt, "arg_temp")?,
            BasicTypeEnum::StructType(st) => self.builder.build_alloca(st, "arg_temp")?,
            BasicTypeEnum::VectorType(vt) => self.builder.build_alloca(vt, "arg_temp")?,
            BasicTypeEnum::ArrayType(at) => self.builder.build_alloca(at, "arg_temp")?,
        };

        self.builder.build_store(arg_value_ptr, arg_value)?;

        // Bitcast to i8* for memcpy
        let arg_i8_ptr = self.builder.build_pointer_cast(
            arg_value_ptr,
            self.context.i8_type().ptr_type(AddressSpace::default()),
            "arg_i8_ptr",
        )?;

        // Use memcpy intrinsic to copy the data
        let memcpy_fn = self
            .module
            .get_function("llvm.memcpy.p0i8.p0i8.i64")
            .unwrap_or_else(|| {
                // llvm.memcpy has void return type
                let void_type = self.context.void_type();
                let fn_type = void_type.fn_type(
                    &[
                        self.context
                            .i8_type()
                            .ptr_type(AddressSpace::default())
                            .into(),
                        self.context
                            .i8_type()
                            .ptr_type(AddressSpace::default())
                            .into(),
                        self.context.i64_type().into(),
                        self.context.bool_type().into(),
                    ],
                    false,
                );
                self.module
                    .add_function("llvm.memcpy.p0i8.p0i8.i64", fn_type, None)
            });

        let _ = self.builder.build_call(
            memcpy_fn,
            &[
                data_i8_ptr.into(),
                arg_i8_ptr.into(),
                self.context
                    .i64_type()
                    .const_int(data_size as u64, false)
                    .into(),
                self.context.bool_type().const_int(0, false).into(),
            ],
            "memcpy",
        )?;

        // Load the complete Result value
        let result_value =
            self.builder
                .build_load(result_struct_type, result_alloca, "result_value")?;
        Ok(result_value)
    }

}
